<?php
namespace app\common\service\wechat;

use think\facade\Log;
use think\facade\Db;
use think\facade\Config;
use WeChatPay\Crypto\AesGcm;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;

class WechatNotify
{
    /**
     * 商家转账到零钱回调统一入口
     */
    public static function handleTransfer()
    {
        // 1. 读取请求体
        $body    = file_get_contents('php://input');
        $headers = array_change_key_case(getallheaders(), CASE_LOWER); // 统一小写键名

        try {
            // 2. 提取头信息
            $serial    = $headers['wechatpay-serial']   ?? '';
            $signature = $headers['wechatpay-signature'] ?? '';
            $timestamp = $headers['wechatpay-timestamp'] ?? '';
            $nonce     = $headers['wechatpay-nonce']     ?? '';

            // 3. 验签
            self::verifySignature($body, $serial, $signature, $timestamp, $nonce);

            // 4. 解析外层 JSON
            $payload = json_decode($body, true, 512, JSON_THROW_ON_ERROR);

            // 5. 解密 resource
            $plainText = AesGcm::decrypt(
                $payload['resource']['ciphertext'],
                Config::get('wechat.secret_key'),
                $payload['resource']['nonce'],
                $payload['resource']['associated_data']
            );
            $data = json_decode($plainText, true, 512, JSON_THROW_ON_ERROR);

            // 6. 日志 + 业务
            Log::info('[WechatTransferNotify] 回调数据' . json_encode($data));
            self::processBusiness($data);

            // 7. 返回微信规定格式
            return ['code' => 'SUCCESS', 'message' => 'OK'];
        } catch (\Throwable $e) {
            Log::error('[WechatTransferNotify] 异常：' . $e->getMessage());
            return ['code' => 'FAIL', 'message' => $e->getMessage()];
        }
    }

    /*--------------------------------------------------
     | 以下为内部私有方法
     *--------------------------------------------------*/

    /**
     * 使用平台证书公钥验签
     * @throws \RuntimeException
     */
    private static function verifySignature(
        string $body,
        string $serial,
        string $signature,
        string $timestamp,
        string $nonce
    ): void {
        // 拼接待验签串
        $message = $timestamp . "\n" . $nonce . "\n" . $body . "\n";

        // 加载平台证书公钥（需提前下载并放到 certs/ 目录）
        $certPath  = Config::get('wechat.platform_cert'); // 如 root_path().'certs/wechatpay.pem'
        $publicKey = PemUtil::loadCertificate($certPath);

        // 微信证书序列号校验（可选）
//        $localSerial = Config::get('wechat.serial');
//        if ($serial !== $localSerial) {
//            throw new \RuntimeException('证书序列号不匹配');
//        }

        // 正式验签
        if (!Rsa::verify($message, $signature, $publicKey)) {
            throw new \RuntimeException('签名验证失败');
        }
    }

    /**
     * 业务处理：更新批次/明细状态
     */
    private static function processBusiness(array $data): void
    {
        // 关键字段
        $outBillNo = $data['out_bill_no'];   // 本地订单号
        $wxBillNo  = $data['transfer_bill_no'];
        $amount    = $data['transfer_amount'];
        $state     = $data['state'];
        $openid    = $data['openid'];
        if($state == 'SUCCESS') {
            Db::name('withdrawal_apply')
            ->where([
                ['order_no', '=', $outBillNo],
                ['open_id', '=', $openid],
            ])
            ->update([
                'status'     => 1,
                'wechat_transfer_id' => $wxBillNo,
                'process_time' => time(),
                'update_time'=> time(),
            ]);
        }
    }
}